package com.ehotting.edsta.mqbd.signal.netty.aop;

import com.ehotting.eaf.netty.constant.ResponseState;
import com.ehotting.eaf.netty.domain.DataAble;
import com.ehotting.edsta.mqbd.api.enums.SysModuleEnum;
import com.ehotting.edsta.mqbd.signal.api.SignalActionConstants;
import com.ehotting.edsta.mqbd.signal.api.bean.MqSignalTcpData;
import com.ehotting.edsta.mqbd.signal.api.domain.netty.*;
import com.ehotting.edsta.mqbd.signal.netty.service.SiMsgStateHandler;
import com.ehotting.mqbd.api.MQDBConstants;
import com.ehotting.mqbd.api.TaskStateActionConstants;
import com.ehotting.mqbd.api.enums.DirectionEnum;
import com.ehotting.mqbd.api.enums.SendTypeEnum;
import com.ehotting.mqbd.api.enums.TopicEnum;
import com.ehotting.mqbd.core.manager.MsgStateManager;
import com.ehotting.mqbd.core.manager.SolverInfoManager;
import com.ehotting.mqbd.core.service.MQService;
import com.ehotting.mqbd.core.manager.AgentLinkManager;
import com.ehotting.mqbd.core.manager.SolverStateManager;
import com.ehotting.mqbd.core.service.TaskStateMQService;
import com.ehotting.mqbd.core.sync.TcpClientMapHelper;
import io.netty.channel.ChannelHandlerContext;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class SIActionAspect {

    private final static Logger logger = LoggerFactory.getLogger(SIActionAspect.class);

    @Autowired
    private MQService mqService;
    @Autowired
    private SolverStateManager solverStateManager;
    @Autowired
    private AgentLinkManager agentLinkManager;
    @Autowired
    private SiMsgStateHandler siMsgStateHandler;
    @Autowired
    private TcpClientMapHelper tcpClientMapHelper;
    @Autowired
    private MsgStateManager msgStateManager;
    @Autowired
    private SolverInfoManager solverInfoManager;
    @Autowired
    private TaskStateMQService taskStateMQService;


    @Pointcut("execution(* com.ehotting.edsta.mqbd.signal.netty.action.*.invoke(..))")
    public void messageAction(){
    }

    @Around(value = "messageAction() && args(ctx,request) ", argNames = "pjp,ctx,request")
    public Object aroundMessageAction(ProceedingJoinPoint pjp,ChannelHandlerContext ctx,DataAble request) throws Throwable{
        Object response  = pjp.proceed(new Object[]{ctx,request});
        handleRequest(ctx,request);
        return response;
    }

    private void handleRequest(ChannelHandlerContext ctx, DataAble request) {
        logger.info("Start sendToQueue.");

        if(request.getDevice()==null){
            /**并且超过多长时间，都为空，应该关闭连接。**/
            logger.error("ClientIp is null,return.");
            return;
        }

        if(request instanceof HeartBeatRequest || request instanceof RegisterRequest){
            logger.info("request instanceof (HeartBeatRequest or RegisterRequest) agentId:{},consumerHost:{},return.",request.getFrom(),request.getDevice());
            return;
        }
        progress100Delay(request,3000);
        sendToQueue(request);

        progress100Delay(request,1000);
        doTaskState(request);

        handleState(ctx,request);



        logger.info("Finish sendToQueue.");
    }

    private void sendToQueue(DataAble request){
        MqSignalTcpData data =  createMQData(request);
        mqService.request(data);
    }

    private void doTaskState(DataAble request){
        if (SignalActionConstants.progressPush.equals(request.getAction()) && ResponseState.SUCCESS.equals(request.getResult())) {
            ProgressPushRequest result = (ProgressPushRequest) request;
            if(result.getProgress()>=100) {
                taskStateMQService.taskFinish(mqService,request.getFrom());
            }
        }

        if (SignalActionConstants.callSimulate.equals(request.getAction()) && ResponseState.SOLVE_FAIL.equals(request.getResult())) {
            taskStateMQService.taskFail(mqService,request.getFrom());
        }

        if (SignalActionConstants.stopSimulate.equals(request.getAction())){
            taskStateMQService.taskCancel(mqService,request.getFrom());
        }
    }

    private MqSignalTcpData createMQData(DataAble request){
        MqSignalTcpData data = MqSignalTcpData.create(TopicEnum.CONCURRENCY,
                request.getDevice(),
                MQDBConstants.DISPATCHER_HOST,
                request.getFrom()
                ,SysModuleEnum.SIGNAL_ANALYSIS.getCode(),"");
        data.setDirection(DirectionEnum.RESPONSE.getCode());
        if (SignalActionConstants.callSimulate.equals(request.getAction()) && ResponseState.SUCCESS.equals(request.getResult())) {
            data.setSendType(new SendTypeEnum[]{SendTypeEnum.REDIS_RESPONSE_BODY});
        }
        handleData(data,request);
        return data;
    }


    private void handleData(MqSignalTcpData data, DataAble request){
        if (SignalActionConstants.callSimulate.equals(request.getAction()) && ResponseState.SOLVE_FAIL.equals(request.getResult())) {
            CallSimulateRequest callSimulateRequest =(CallSimulateRequest)request;
            LogPushRequest logPushRequest = new LogPushRequest(request.getUserId(),
                    agentLinkManager.getProjectId(request.getFrom()),
                    "求解失败:"+callSimulateRequest.getErrorInfo());
            logPushRequest.setFrom(request.getFrom());
            data.setResponse(logPushRequest);
            siMsgStateHandler.handleDelete(request.getFrom());
        }else{
            data.setResponse(request);
        }
    }

    /**如果求解进度达到100，结果睡眠3秒，作为结果文件先发送完成**/
    private void progress100Delay(DataAble request,long sleep){
        if(SignalActionConstants.progressPush.equals(request.getAction())){
            ProgressPushRequest result = (ProgressPushRequest) request;
            if(result.getProgress()>=100){
                try {
                    Thread.sleep(sleep);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void handleState(ChannelHandlerContext ctx, DataAble request){
        if (SignalActionConstants.progressPush.equals(request.getAction()) ){
            ProgressPushRequest result = (ProgressPushRequest) request;
            if(result.getProgress()<100){
                return;
            }
            solverStateManager.setSolverFree(SysModuleEnum.SIGNAL_ANALYSIS.getCode(),tcpClientMapHelper.getSolverIp(ctx));
            solverInfoManager.deleteSolverRefAgentId(request.getFrom());
            shutdown(ctx,request);
        }

        if (SignalActionConstants.stopSimulate.equals(request.getAction())){
            if(msgStateManager.getByAgentIdAndSolving(request.getFrom())!=null){
                solverStateManager.setSolverFree(SysModuleEnum.SIGNAL_ANALYSIS.getCode(),tcpClientMapHelper.getSolverIp(ctx));
                solverInfoManager.deleteSolverRefAgentId(request.getFrom());
            }
            shutdown(ctx,request);
        }
    }


    private void shutdown(ChannelHandlerContext ctx,DataAble request){
        siMsgStateHandler.handleDelete(request.getFrom());
        Runnable closeTcp = new Runnable() {
            @Override
            public void run() {
                logger.info("Solver[AgentId:{},ip:{}] 更新为空闲状态，去掉和agentId/ip的绑定",request.getFrom(),request.getDevice());
                tcpClientMapHelper.shutdownClientDelay(request.getFrom());

            }
        };

        Thread t = new Thread(closeTcp);
        t.start();
    }



}